using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections;

namespace UmassGrader
{
    /// <summary>
    /// holds all the data for a group of students enrolled in a programing class
    /// </summary>
    /// <remarks></remarks>
    [Serializable]
    public class ClassSection
    {

        /// <summary>
        /// every student (enrolled or withdrawn)
        /// </summary>
        public List<Student> students;
        /// <summary>
        /// a list of possible assignments to grade
        /// </summary>
        public List<Assignment> assignments;

        /// <summary>
        /// the currently selected student (NB:selected, not checked)
        /// </summary>
        public Student CurrentStudent;
        /// <summary>
        /// the assignment currently selected in the combo box
        /// </summary>
        public Assignment currentAssignment; //List<Assignment>.Enumerator

        /// <summary>
        /// The location of the list of students
        /// </summary>
        /// protected String LocalDir 
        /// protected String RemoteDir 
        public String StuPath;
        /// <summary>
        /// The location of the list of assignments
        /// </summary>
        public String ProgPath;

        /// <summary>
        /// this is where we will store the output of the compiler and running programs
        /// </summary>
        public String programOutput;
        /// <summary>
        /// this is like a teaching assistant that tells the teacher where to file stuff
        /// </summary>
        public PathFinder pf;

        /// <summary>
        /// sets up the class Section with null values.
        /// </summary>
        /// <remarks>TODO(Ben Viall): set up a constructor that takes the grader setting file 
        ///          and facilitates autoload settings on startup</remarks>
        public ClassSection()
        {
            students = new List<Student>();
            assignments = new List<Assignment>();
            StuPath = "";
            ProgPath = "";
            try { pf = new PathFinder(); }
            catch { };
        }

        /// <summary>
        /// create the command line arguments for cl.exe for a specific student/program pair
        /// </summary>
        /// <param name="stu">the student whose project you want to compile</param>
        /// <param name="prog">the project you want to compile</param>
        public String ComplierFlags(Student stu, Assignment prog)
        {
            String s = "";
            s += prog.compilerFlags;
            s += " /Fe\"" + pf.executablePath(stu, prog) + "\"";
            s += " /Fo\"" + pf.objectPath(stu, prog) + "\"";
            for (int i = 0; i < prog.compilableFiles().Count; i++)
                s += " \"" + pf.compilablesPath(stu, prog, i, PathFinder.Remote) + "\"";
            return s;
        }
        /// <summary>
        /// check to see if a submision has been graded yet
        /// </summary>
        /// <param name="stu">the student to check</param>
        /// <param name="prog">the project to check</param>
        public bool isGraded(Student stu, Assignment prog)
        {
            return File.Exists(pf.gradePath(stu, prog, PathFinder.Local));
        }
        /// <summary>
        /// check if a student has a specific grade on a project
        /// </summary>
        /// <param name="stu">the student to check</param>
        /// <param name="prog">the project your checking</param>
        /// <param name="grd">the grade you want to check for</param>
        public bool hasGradeof(Student stu, Assignment prog, int grd)
        {
            String lgPath = pf.gradePath(stu, prog, PathFinder.Local);
            if (!System.IO.File.Exists(lgPath)) return false;
            StreamReader infile = new StreamReader(lgPath);
            infile.ReadLine();
            infile.ReadLine();
            infile.ReadLine();
            String gradeline = infile.ReadLine();
            int givenGrade = int.Parse(gradeline.Substring(6));
            return (givenGrade == grd);
        }


        /// <summary>
        /// get the submited file from the remote directory
        /// </summary>
        /// <remarks></remarks>
        /// <param name="stu">the student whose submission</param>
        /// <param name="prog">the program</param>
        public void RetriveFiles(Student stu, Assignment prog)
        {
            for (int i = 0; i < prog.submitList.Count; i++)
                if (File.Exists(pf.submitablesPath(stu, prog, i, 1)))
                {
                    File.Copy(pf.submitablesPath(stu, prog, i, 1), pf.submitablesPath(stu, prog, i, 0), true);
                    File.SetAttributes(pf.submitablesPath(stu, prog, i, 0), FileAttributes.Normal);
                }

        }


        /// <summary>
        /// this will try to show the *.grd file and the *.prn file of [userName] in two textboxes
        /// </summary>
        /// <param name="stu">the student whose program should be displayed</param>
        /// <param name="prog">the program</param>
        /// <param name="txtMain">big text box</param>
        /// <param name="txtGrade">little text box</param>
        /// <remarks>TODO(ben viall): should include a parameter for the picture box</remarks>
        public void DisplayProgram(Student stu, Assignment prog, ref TextBox txtMain, ref TextBox txtGrade)
        {
            String prnPath = pf.printPath(stu, prog);
            String lgPath = pf.gradePath(stu, prog, 0);

            //get the prn file first
            if (!File.Exists(prnPath))
            {
                txtMain.Text = "You Havent Run this Program Yet";
                return;
            }
            StreamReader infile = new StreamReader(prnPath);
            txtMain.Text = infile.ReadToEnd().Replace("\n", "\r").Replace("\r", "\n");
            infile.Close();

            //get the previous grade if it exists
            if (!File.Exists(lgPath))
            {
                txtGrade.Text = "No previous grade file";
                return;
            }
            infile = new StreamReader(lgPath);
            txtGrade.Text = infile.ReadToEnd();
            infile.Close();
        }


        /// <summary>
        /// copy local grade to remote grade
        /// </summary>
        /// <param name="stu">the user whose grade you want to upload</param>
        /// <param name="prog">the project that is being graded</param>
        /// <remarks></remarks>
        public void putGradeFile(Student stu, Assignment prog)
        {
            String lgPath = pf.gradePath(stu, prog, PathFinder.Local);
            String rgPath = pf.gradePath(stu, prog, PathFinder.Remote);
            if (File.Exists(lgPath))
                File.Copy(lgPath, rgPath, true);
            else
                MessageBox.Show(String.Format("unable to place grade file for {0}", stu.userName));
        }

        /// <summary>
        /// get the checked students,"currently selected project" files from the remote Dir
        /// </summary>
        /// <param name="list">has students username in the listbox</param>
        /// <param name="worker">this is the background worker that handles the backround taske</param>
        /// <param name="getAll">get all, if true; get checked only, if false</param>
        /// <remarks></remarks>
        public void downloadFiles(CheckedListBox list, System.ComponentModel.BackgroundWorker worker, Boolean getAll)
        {
            if (currentAssignment == null)
            {
                MessageBox.Show("Select a program to download!");
                return;
            }
            if (!Directory.Exists(currentAssignment.DestinationDir))
                Directory.CreateDirectory(currentAssignment.DestinationDir);

            IEnumerator currStu = ((IEnumerator)list.CheckedItems.GetEnumerator());
            String userName;
            int i = 0;
            int max = list.Items.Count;
            while (currStu.MoveNext())
            {
                userName = ((Student)currStu.Current).userName;

                worker.ReportProgress(i * 100 / max, userName);
                this.RetriveFiles(((Student)currStu.Current), currentAssignment);

                i++;
                if (worker.CancellationPending) break;
            }
        }
        /// <summary>
        /// send the grade files to the students remote directorys
        /// </summary>
        /// <param name="list">holds the selected students</param>
        /// <remarks></remarks>
        public void uploadGrades(CheckedListBox.CheckedItemCollection  list, BackgroundWorker worker)
        {
            Student stu;
            IEnumerator stuEnumerator;
            int i = 0;
            int max = list.Count;
            String userName;
            if (currentAssignment == null)
            {
                MessageBox.Show("Select a program to upload!");
                return;
            }

            stuEnumerator = list.GetEnumerator();

            while (stuEnumerator.MoveNext())
            {
                userName = ((Student)stuEnumerator.Current).userName;
                worker.ReportProgress(i * 100 / max, userName);
                stu = ((Student)stuEnumerator.Current);
                if (File.Exists(pf.gradePath(stu, currentAssignment, PathFinder.Local)))
                    File.Copy(pf.gradePath(stu, currentAssignment, PathFinder.Local),
                              pf.gradePath(stu, currentAssignment, PathFinder.Remote), true);
                i++;
                if (worker.CancellationPending) break;
            }
        }
        /// <summary>
        /// compile and run the [checked] students 
        /// </summary>
        /// <param name="list">holds the list of students</param>
        /// <param name="prog">this is a copy of the program you want to run</param>
        /// <param name="worker">this is the background worker that handles all the stuff</param>
        /// <param name="runAll">run all(true);run checked(false)</param>
        /// <remarks></remarks>
        /// 
        public void runPrograms(ref CheckedListBox.CheckedItemCollection list, Assignment prog, BackgroundWorker worker, Boolean runAll)
        {
            if (prog == null)
            {
                MessageBox.Show("select a project to compile");
                return;
            }

            String userName;
            StreamWriter prnFile;
            //do Run stuff
            int exitcode = -1;

            IEnumerator currStu = list.GetEnumerator();
            int max = list.Count;
            int i = 0;

            while (currStu.MoveNext())
            {
                //get a copy of the current student
                userName = ((Student)currStu.Current).userName;
                System.Console.WriteLine("running {0}\n",userName);
                worker.ReportProgress(i * 100 / max, userName);
                i++;

                //open the Print file
                try
                {
                    prnFile = new StreamWriter(pf.printPath(((Student)currStu.Current), prog));

                    //you may begin your run gold leader
                    outputPRNHeader(prnFile, ((Student)currStu.Current), prog);
                    outputPRNsrcFiles(prnFile, ((Student)currStu.Current), prog);
                    exitcode = outputPRNCompile(prnFile, ((Student)currStu.Current), prog);
                    if (exitcode == 0)
                    {
                        outputPRNRun(prnFile, ((Student)currStu.Current),
                                     prog, /*int.Parse(Form1.txtProgTimeout.Text)*/2000);
                    }
                    exitcode = -1;
                    prnFile.Close();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.StackTrace + "\n" + ex.Message);
                }

                if (worker.CancellationPending)  break;
            }
        }
        /// <summary>
        /// outputs the header for a submision report
        /// </summary>
        /// <param name="prnFile">the output stream that the report should go to</param>
        /// <param name="stu">the student you are reporting on</param>
        /// <param name="prog">the project you are reporting on</param>
        public void outputPRNHeader(StreamWriter prnFile, Student stu, Assignment prog)
        {
            DateTime due;
            switch (stu.LabSection)
            {
                case DayOfWeek.Monday: due = prog.dueDateList[0]; break;
                case DayOfWeek.Tuesday: due = prog.dueDateList[1]; break;
                case DayOfWeek.Wednesday: due = prog.dueDateList[2]; break;
                case DayOfWeek.Thursday: due = prog.dueDateList[3]; break;
                case DayOfWeek.Friday: due = prog.dueDateList[4]; break;
                default: due = prog.dueDateList[0]; break;
            }
            due = due.AddHours(23);
            due = due.AddMinutes(59);
            due = due.AddSeconds(59);

            //TODO: this class should not be referencing Form1. extract repeatchar to somewhere else
            prnFile.WriteLine(Form1.repeatchar('*', 70));
            prnFile.WriteLine(String.Format("Name: {0}", stu.fullName));
            prnFile.WriteLine(String.Format("Prog: {0}", prog.dispName));
            prnFile.WriteLine(String.Format("grad: {0}", "@@@"));
            prnFile.WriteLine(String.Format("user: {0}", stu.userName));
            prnFile.WriteLine(String.Format("Due: {0}", due.ToString()));
            prnFile.WriteLine(String.Format("Graded: {0}", DateTime.Now.ToString()));

            DateTime submitted;
            Boolean missing = false;
            // TODO(Ben Viall): at some point you should think about the idea of ENCAPSULATION
            // its bad to get submitlist from another class
            for (int i = 0; i < this.currentAssignment.submitList.Count; i++)
            {
                if (File.Exists(pf.submitablesPath(stu, prog, i, PathFinder.Local)))
                {
                    submitted = File.GetLastWriteTime(pf.submitablesPath(stu, prog, i, PathFinder.Local));
                    prnFile.WriteLine(String.Format("{0} Submitted: {1}", prog.submitList[i], submitted.ToString()));
                    if (submitted > due)
                        prnFile.WriteLine("Late by:{0} days",(((submitted - due).Days) + 1));
                }
                else
                {
                    missing = true;
                    prnFile.WriteLine(String.Format("{0} Not Submitted", prog.submitList[i]));
                }
                prnFile.WriteLine(String.Format("Comments: {0}", "None"));

            }
            if (missing)
            {
                prnFile.WriteLine("Can't find some files. Directory of files follows: \n");
                String[] filelist;
                String[] dirlist;
                if (Directory.Exists(pf.remoteStudentDir(stu)))
                {
                    dirlist = Directory.GetDirectories(pf.remoteStudentDir(stu));
                    filelist = Directory.GetFiles(pf.remoteStudentDir(stu));
                    foreach (String dir in dirlist) prnFile.WriteLine("+{0}", dir);
                    foreach (String fil in filelist) prnFile.WriteLine("-{0}", fil);
                    prnFile.WriteLine(Form1.repeatchar('*', 70));
                }
                else
                {
                    prnFile.WriteLine("Can't Find the Source Directoryn");
                }
            }
        }
        /// <summary>
        /// outputs the submitted files to the submision report
        /// </summary>
        /// <param name="prnFile">the output stream that the report should go to</param>
        /// <param name="stu">the student you are reporting on</param>
        /// <param name="prog">the project you are reporting on</param>
        public void outputPRNsrcFiles(StreamWriter prnFile, Student stu, Assignment prog)
        {
            //TODO(ben viall): currently blacklisting jpegs from being displayed...find a better way
            StreamReader srcFile;
            String temp;
            int j;
            for (int i = 0; i < prog.submitList.Count; i++)
            {
                prnFile.WriteLine(prog.submitList[i]);
                if (!prog.submitList[i].EndsWith(".jpg") &&
                    File.Exists(pf.submitablesPath(stu, prog, i, PathFinder.Local)))
                {
                    prnFile.WriteLine("** start file " + Form1.repeatchar('*', 56));
                    srcFile = new StreamReader(pf.submitablesPath(stu, prog, i, PathFinder.Local));
                    j = 1;
                    while (!srcFile.EndOfStream)
                    {
                        temp = srcFile.ReadLine();
                        prnFile.WriteLine("/*" + j.ToString().PadLeft(4) + "*/ " + temp);
                        j++;
                    }
                }
            }
        }
        /// <summary>
        /// outputs the result of attempted compilation to the submission report
        /// </summary>
        /// <param name="prnFile">the output stream that the report should go to</param>
        /// <param name="stu">the student you are reporting on</param>
        /// <param name="prog">the project you are reporting on</param>
        public int outputPRNCompile(StreamWriter prnFile, Student stu, Assignment prog)
        {
            int exitcode = -10;
            if (prog.needsCompile)
            {
                exitcode = Compile(stu, prog);
                if (exitcode == 0)
                {
                    prnFile.WriteLine("** compiled " + Form1.repeatchar('*', 57));
                }
                else
                {
                    prnFile.WriteLine("** could not compile " + Form1.repeatchar('*', 70 - 21));
                }
                prnFile.WriteLine(programOutput);
                programOutput = "";
            }

            return exitcode;
        }
        /// <summary>
        /// outputs the result of program execution to the submision report
        /// </summary>
        /// <param name="prnFile">the output stream that the report should go to</param>
        /// <param name="stu">the student you are reporting on</param>
        /// <param name="prog">the project you are reporting on</param>
        /// <param name="timeout">the time a project has to run before it is premtivly shut down</param>
        public void outputPRNRun(StreamWriter prnFile, Student stu, Assignment prog, int timeout)
        {
            int startIndex, stopIndex;
            if (prog.inputRedirectList.Count == 0)
            {
                startIndex = -1;
                stopIndex = 0;
            }
            else
            {
                startIndex = 0;
                stopIndex = prog.inputRedirectList.Count;
            }

            for (int i = startIndex; i < stopIndex; i++)
            {
                //Todo: make runProgram throw exceptions and catch them rather then return integers.
                if (runProgram(stu, prog, i, 1) == -2)
                {
                    MessageBox.Show("no input file found");
                }
                prnFile.WriteLine("********** console output **********");
                prnFile.WriteLine(programOutput);
                programOutput = "";

                StreamReader readOutputfile;
                String outputfilePath;
                for (int k = 0; k < prog.outputFileList.Count - 1; i++)
                {
                    prnFile.WriteLine(String.Format("********** File {0} **********", prog.outputFileList[k]));
                    outputfilePath = pf.outputDataFilePath(prog, k);
                    //C:\ECE16X\1730\ece161\workingDir
                    if (File.Exists(outputfilePath))
                    {
                        try
                        {
                            readOutputfile = new StreamReader(outputfilePath);
                            prnFile.WriteLine(readOutputfile.ReadToEnd());
                            readOutputfile.Close();
                            File.Delete(outputfilePath);
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.StackTrace);
                        }
                    }
                    else
                    {
                        prnFile.WriteLine("  F I L E   N O T   F O U N D");
                    }
                }
            }

            //if Form1.chkAutoDelete.Checked {
            String opath = pf.objectPath(stu, prog);
            String epath = pf.executablePath(stu, prog);
            //if File.Exists(opath) { File.Delete(opath)
            //if File.Exists(epath) { File.Delete(epath)
            //}
        }
        /// <summary>
        /// display the List(of Students) in the form
        /// </summary>
        /// <param name="list">checked list box to display students in</param>
        /// <param name="showWithdrawn">option to hide withdrawn students</param>
        /// <remarks></remarks>
        public void populateStuList(CheckedListBox list, Boolean showWithdrawn)
        {
            list.Items.Clear();
            foreach (Student stu in this.students)
                if (stu.enrolled || showWithdrawn)
                    list.Items.Add(stu);
        }
        /// <summary>
        /// display the List(of Assignments) in the Form
        /// </summary>
        /// <param name="box">control to display the assignments in</param>
        /// <remarks></remarks>
        public void populateProglist(ComboBox box)
        {
            box.Items.Clear();
            foreach (Assignment prog in this.assignments)
                box.Items.Add(prog.dispName);

        }
        /// <summary>
        /// loadlist of Students from file
        /// </summary>
        /// <param name="Path">location of the data file</param>
        /// <param name="clear">remove old data if true</param>
        /// <remarks>can we use StuPath instead of passing an argument</remarks>
        public void getStudentList(String Path, Boolean clear)
        {
            if (!File.Exists(Path)) return;
            StreamReader infile = new StreamReader(Path);
            if (clear) this.students.Clear();
            while (infile.Peek() != -1)
                this.students.Add(new Student(infile));
            infile.Close();

        }
        /// <summary>
        /// Load list of Assignments from file
        /// </summary>
        /// <param name="Path">location of the data file</param>
        /// <remarks>can we use the field progpath rather than passing as an argument?</remarks>
        public void getProgramList(String Path)
        {
            if (!File.Exists(Path)) return;
            this.assignments.Clear();
            StreamReader infile = new StreamReader(Path);
            infile.ReadLine(); // ignore header
            while (infile.Peek() != -1)
                this.assignments.Add(new Assignment(infile));
            infile.Close();
        }
        /// <summary>
        /// store data to a file
        /// </summary>
        /// <param name="path">path to store data</param>
        /// <remarks>format: one piece of data per line
        /// 1) local dir
        /// 2) remote Dir
        /// 3) Student data file path
        /// 4) Program data file Path
        /// </remarks>
        public void storeToFile(String path)
        {
            StreamWriter outfile = new StreamWriter(path);
            outfile.WriteLine(pf.localDir);
            outfile.WriteLine(pf.RemoteDir);
            outfile.WriteLine(StuPath);
            outfile.WriteLine(ProgPath);
            outfile.Close();
        }
        /// <summary>
        /// retrive settings data from file (optionally get stu and prog data)
        /// </summary>
        /// <param name="path">settings File path</param>
        /// <param name="autoload">get stu and prog data</param>
        /// <remarks></remarks>
        public void restoreFromFile(String path, Boolean autoload)
        {
            StreamReader infile = new StreamReader(path);
            pf.localDir = infile.ReadLine();
            pf.RemoteDir = infile.ReadLine();

            StuPath = infile.ReadLine();
            ProgPath = infile.ReadLine();
            if (autoload)
            {
                getProgramList(ProgPath);
                getStudentList(StuPath, true);
            }
        }

        /// <summary>
        /// retrive the grade of a students previously graded transmision
        /// </summary>
        /// <param name="stu">the student the grade applies to</param>
        /// <param name="prog">the project the grade applies to</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public int grade(Student stu, Assignment prog)
        {
            String lgPath = pf.gradePath(stu, prog, PathFinder.Local);
            StreamReader infile;
            if (!File.Exists(lgPath)) return -1;
            try
            {
                infile = new StreamReader(lgPath);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                return -1;
            }

            infile.ReadLine();
            infile.ReadLine();
            infile.ReadLine();
            String gradeline = infile.ReadLine();
            infile.Close();
            return int.Parse(gradeline.Substring(6));
        }

        //compiler
        /// <summary>
        /// compiles the programing the M$ VS C compiler
        /// </summary>
        /// <param name="stu">the student whose project you want to compile</param>
        /// <param name="prog">the project you want to compile</param>
        /// <returns>the result of running the compiler</returns>
        /// <remarks> the project that is compiled is the myclasssection.currentAssignment
        /// all compiler output (stdout and std err) is sent to form1.programOutput</remarks>
        public int Compile(Student stu, Assignment prog)
        {
            Process program = new Process();
            ProcessStartInfo progSI = new ProcessStartInfo();
            int myexit;
            progSI.FileName = "cl.exe";
            progSI.UseShellExecute = false;
            progSI.RedirectStandardError = true;
            progSI.RedirectStandardOutput = true;
            progSI.CreateNoWindow = true;
            progSI.WorkingDirectory = prog.workingDir;

            progSI.Arguments = "";
            progSI.Arguments += ComplierFlags(stu, prog);

            //copy files to the working directory with original names before compilation
            if (!Directory.Exists(prog.workingDir)) Directory.CreateDirectory(prog.workingDir);

            for (int index = 0; index < prog.submitList.Count; index++)
                if (File.Exists(pf.submitablesPath(stu, prog, index, PathFinder.Local)))
                    File.Copy(pf.submitablesPath(stu, prog, index, PathFinder.Local), prog.workingDir + "\\" + prog.submitList[index], true);


            program.StartInfo = progSI;
            program.OutputDataReceived += new DataReceivedEventHandler(programOutputHandler);
            program.ErrorDataReceived += new DataReceivedEventHandler(programOutputHandler);


            programOutput = "";
            program.Start();
            program.BeginOutputReadLine();
            program.WaitForExit(5000);

            //remove the files that we copied into the working dir
            for (int index = 0; index < prog.submitList.Count; index++)
            {
                if (File.Exists(prog.workingDir + "\\" + prog.submitList[index]))
                {
                    File.Delete(prog.workingDir + "\\" + prog.submitList[index]);
                }
            }
            //remove the object files
            String objpath;
            for (int index = 0; index < prog.compilableFiles().Count; index++)
            {
                objpath = prog.workingDir + "\\" + Path.ChangeExtension(prog.compilableFiles()[index], ".obj");
                if (File.Exists(objpath))
                {
                    File.Delete(objpath);
                }
            }
            myexit = program.ExitCode;
            program.Close();
            return myexit;
        }
        //'run Program
        /// <summary>
        /// runs "stu"'s compiled sourcefile(if it exists) with a specified input file
        /// </summary>
        /// <param name="stu">Student to be run</param>
        /// <param name="prog">Assignment being corrected</param>
        /// <param name="infilenum">-1 to indicate no input, otherwise [projectname].In[infilenum]</param>
        /// <param name="timeout">number of seconds to wait for a executable to run before being killed</param>
        /// <returns>0 if sucessful;
        /// -1 if exe DNE;
        /// -2 if infile DNE;
        /// -3 if program took to long to run</returns>
        /// <remarks>uses myclassSection.currentProject</remarks>
        public int runProgram(Student stu, Assignment prog, int infilenum, int timeout)
        {
            Process program1 = new Process();
            StreamReader infile;
            String myWorkingDir = prog.workingDir;
            String exePath = pf.executablePath(stu, prog);

            if (!Directory.Exists(myWorkingDir)) Directory.CreateDirectory(myWorkingDir);
            if (!File.Exists(exePath)) return -1;
            if (infilenum > -1)
            {
                if (!File.Exists(pf.inputRedirectPath(prog, infilenum, 0))) return -2;
                //File.Copy(pf.inputRedirectPath(prog, infilenum, 0), pf.inputRedirectPath(prog, infilenum, 1))
            }
            program1.StartInfo.FileName = exePath;
            program1.StartInfo.UseShellExecute = false;
            program1.StartInfo.RedirectStandardInput = true;
            program1.StartInfo.RedirectStandardOutput = true;
            program1.StartInfo.CreateNoWindow = true;
            program1.StartInfo.WorkingDirectory = myWorkingDir;

            program1.OutputDataReceived += new DataReceivedEventHandler(programOutputHandler);
            program1.ErrorDataReceived += new DataReceivedEventHandler(programOutputHandler);

            for (int i = 0; i < prog.inputFileList.Count; i++)
                if (File.Exists(pf.inputDataFilePath(prog, i, 0)))
                    File.Copy(pf.inputDataFilePath(prog, i, 0), pf.inputDataFilePath(prog, i, 1), true);



            //start program running
            program1.Start();
            program1.BeginOutputReadLine();

            //reroute input file if needed
            if (infilenum > -1)
            {
                infile = new StreamReader(pf.inputRedirectPath(prog, infilenum, 0));
                program1.StandardInput.Write(infile.ReadToEnd());
                infile.Close();
            }

            //begin timing
            if (!program1.WaitForExit(timeout * 1000))
            {
                program1.Kill();
                program1.WaitForExit();
                return -3;
            }

            program1.CancelOutputRead();
            program1.Close();
            program1.Refresh();
            return 0;
        }
        /// <summary>
        /// handles asyncrounous output from compilation and execution
        /// </summary>
        /// output Handler
        private void programOutputHandler(Object sender, DataReceivedEventArgs e)
        {
            programOutput += e.Data + "\n";
        }

    }

}
